fix(staged): keep git subprocesses from wedging the user's terminal#757
Conversation
Centralize TTY hardening in `run_with_env` so every git invocation gets
both layers: `GIT_TERMINAL_PROMPT=0` + `GIT_SSH_COMMAND=ssh -o
BatchMode=yes -o ConnectTimeout=10` make ssh refuse to prompt at the
semantic level, and `setsid()` via `pre_exec` ensures ssh can't
`open("/dev/tty")` to bypass piped stdio. The previous fix (#756) only
covered the env-capture shells; background_sync's `git fetch` still
inherited the user's ctty and could surface a passphrase prompt that
left the outer zsh wedged on EIO.
Signed-off-by: Matt Toohey <contact@matttoohey.com>
force_non_interactive unconditionally clobbered any GIT_SSH_COMMAND carried in by the captured shell snapshot — silently overriding corporate ssh wrappers that pin identity files, route through a jump host, or talk to an SSH CA helper. Skip the default injection when the captured env already defines GIT_SSH_COMMAND; trust those users to keep their wrapper non-interactive and lean on detach_from_ctty (the structural half of the pair) to keep an errant prompt from stealing the outer TTY. Signed-off-by: Matt Toohey <contact@matttoohey.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 449355efc5
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| command.env( | ||
| "GIT_SSH_COMMAND", | ||
| "ssh -o BatchMode=yes -o ConnectTimeout=10", | ||
| ); |
There was a problem hiding this comment.
Preserve configured SSH commands
For repos that rely on core.sshCommand (for example to select a deploy key, wrapper, or non-default SSH binary), injecting GIT_SSH_COMMAND here makes Git ignore that repo/user config; I checked the Git docs for core.sshCommand, which state it is overridden when GIT_SSH_COMMAND is set. This affects the existing fetch/push paths that call cli::run, so those repos can start failing authentication even though they worked before unless the user also exports GIT_SSH_COMMAND.
Useful? React with 👍 / 👎.
Summary
Git subprocesses spawned by staged could wedge the outer terminal when ssh fell back to prompting for credentials. ssh would
open(\"/dev/tty\")directly — bypassing our piped stdio — andtcsetpgrpthe user's TTY onto its own process group. When that group died, the outer zsh got stuck with EIO.This change applies two layers of defense to every
gitinvocation ingit/cli.rs:force_non_interactivesetsGIT_TERMINAL_PROMPT=0and a defaultGIT_SSH_COMMANDwithBatchMode=yesandConnectTimeout=10so ssh fails fast withPermission deniedinstead of prompting. A user-providedGIT_SSH_COMMANDfrom the captured shell env (e.g. a corporate ssh wrapper) is preserved.detach_from_cttycallssetsid()inpre_execso the child has no controlling TTY to grab, even if a future refactor reattaches stdio.Includes unit tests covering both the default-injection and user-respects paths for
GIT_SSH_COMMAND.Test plan
cargo testinapps/staged/src-tauri(covered by CI: crates-test)